"""
依赖项模块
包含API路由中使用的依赖项函数
"""
from typing import Generator, Optional, List
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
from pydantic import ValidationError
from motor.motor_asyncio import AsyncIOMotorDatabase
import redis.asyncio as redis
from minio import Minio

from app.core.config import settings
from app.core.database import get_database, get_redis, get_minio
from app.core.security import verify_token
from app.models.user import TokenData, UserRole
from app.services.permission_service import PermissionService
import logging

logger = logging.getLogger(__name__)

# OAuth2密码承载令牌
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_STR}/auth/login")

async def get_db() -> Generator[AsyncIOMotorDatabase, None, None]:
    """获取数据库连接"""
    db = get_database()
    try:
        yield db
    finally:
        # Motor客户端不需要显式关闭连接
        pass

async def get_redis_client() -> Generator[Optional[redis.Redis], None, None]:
    """获取Redis客户端"""
    redis_client = get_redis()
    try:
        yield redis_client
    finally:
        # Redis连接在应用关闭时统一关闭
        pass

def get_minio_client() -> Minio:
    """获取MinIO客户端"""
    return get_minio()

async def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> dict:
    """获取当前用户"""
    
    # logger.info(f"get_current_user called with token preview: {token[:20] if token else 'None'}...")
    
    # credentials_exception = HTTPException(
    #     status_code=status.HTTP_401_UNAUTHORIZED,
    #     detail="Could not validate credentials",
    #     headers={"WWW-Authenticate": "Bearer"},
    # )
    
    try:
        # 验证令牌
        logger.info("开始验证token...")
        payload = verify_token(token)
        logger.info(f"Token验证成功，payload: {payload}")
        
        user_id = payload.get("user_id")
        email = payload.get("email")
        
        if user_id is None or email is None:
            logger.warning(f"Missing user_id or email in token payload: user_id={user_id}, email={email}, full_payload={payload}")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication token: missing user information",
                headers={"WWW-Authenticate": "Bearer"},
            )
            
        token_data = TokenData(
            user_id=user_id,
            email=email,
            system_roles=payload.get("roles", []),
            permissions=payload.get("permissions", [])
        )
        logger.info(f"Token数据解析成功: user_id={user_id}, email={email}")
    except (JWTError, ValidationError) as e:
        logger.warning(f"Token validation error: {str(e)}, token_preview: {token[:20] if token else 'None'}...")
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication token format",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 从数据库获取用户信息
    from bson import ObjectId
    try:
        # 验证 user_id 是否为有效的 ObjectId 格式
        if not ObjectId.is_valid(token_data.user_id):
            logger.warning(f"Invalid ObjectId format in token: {token_data.user_id}, token payload: {payload}")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication token: user ID format error",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        user = await db.users.find_one({"_id": ObjectId(token_data.user_id)})
        
        if user is None:
            logger.warning(f"User not found in database for user_id: {token_data.user_id}, email: {token_data.email}")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Authentication failed: user not found",
                headers={"WWW-Authenticate": "Bearer"},
            )
            
    except HTTPException:
        # 重新抛出 HTTPException
        raise
    except Exception as e:
        logger.error(f"Database query error: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Internal server error during authentication"
        )
    
    # 计算用户权限
    user_dict = {
        "user_id": str(user["_id"]),
        "username": user.get("username", user.get("email", "")),
        "email": user["email"],
        "name": user["name"],
        "system_roles": user.get("system_roles", []),
        "permissions": user.get("permissions", []),
        "department_id": user.get("department_id"),
        "position": user.get("position"),
        "phone": user.get("phone"),
        "avatar": user.get("avatar"),
        "status": user.get("status", "active"),
        "is_verified": user.get("is_verified", True),
        "created_at": user.get("created_at"),
        "updated_at": user.get("updated_at"),
        "last_login": user.get("last_login"),
        "login_count": user.get("login_count", 0)
    }
    
    # 获取角色代码（用于兼容性）
    role_codes = []
    if user_dict["system_roles"]:
        try:
            rids = [ObjectId(rid) for rid in user_dict["system_roles"] if ObjectId.is_valid(rid)]
            if rids:
                roles = await db.roles.find({"_id": {"$in": rids}}).to_list(None)
                role_codes = [r.get("code") for r in roles]
        except Exception as e:
            logger.error(f"Error fetching role codes: {str(e)}")
            
    user_dict["roles"] = role_codes
    
    # 使用PermissionService计算完整权限（包括自定义角色权限）
    user_dict["permissions"] = await PermissionService.calculate_user_permissions(user_dict, db)
    
    return user_dict

async def get_current_active_user(
    current_user: dict = Depends(get_current_user)
) -> dict:
    """获取当前活跃用户"""
    # 在实际应用中，可以检查用户状态是否为活跃
    return current_user

def check_permissions(required_permissions: List[str] = None):
    """
    检查用户是否拥有所有所需权限（AND关系）
    
    Args:
        required_permissions: 需要的权限列表，如果为None或空列表，则不检查权限
        
    Returns:
        依赖注入函数，返回当前用户信息
    """
    async def permission_checker(current_user: dict = Depends(get_current_user)):
        if not required_permissions:
            return current_user
        
        # 使用PermissionService批量检查权限
        if not PermissionService.has_permissions(current_user, required_permissions):
            missing_permissions = [
                perm for perm in required_permissions 
                if not PermissionService.has_permission(current_user, perm)
            ]
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"权限不足: 需要 {', '.join(missing_permissions)} 权限"
            )
        
        return current_user
    
    return permission_checker


def check_any_permission(required_permissions: List[str] = None):
    """
    检查用户是否拥有任一所需权限（OR关系）
    
    Args:
        required_permissions: 需要的权限列表，用户只需拥有其中一个权限
        
    Returns:
        依赖注入函数，返回当前用户信息
    """
    async def permission_checker(current_user: dict = Depends(get_current_user)):
        if not required_permissions:
            return current_user
        
        # 使用PermissionService检查是否有任一权限
        if not PermissionService.has_any_permission(current_user, required_permissions):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"权限不足: 需要以下权限之一: {', '.join(required_permissions)}"
            )
        
        return current_user
    
    return permission_checker

def check_roles(required_roles: List[str] = None):
    """
    检查用户是否拥有所需角色（任一角色即可）
    
    Args:
        required_roles: 需要的角色列表，如果为None或空列表，则不检查角色
        
    Returns:
        依赖注入函数，返回当前用户信息
    """
    async def role_checker(current_user: dict = Depends(get_current_user)):
        if not required_roles:
            return current_user
        
        # 使用PermissionService检查角色
        if not PermissionService.has_roles(current_user, required_roles):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"角色不足: 需要 {', '.join(required_roles)} 角色之一"
            )
        
        return current_user
    
    return role_checker

async def get_current_admin(
    current_user: dict = Depends(get_current_user)
) -> dict:
    """
    获取当前管理员用户
    检查用户是否拥有管理员角色或通配符权限
    """
    user_roles = current_user.get("roles", [])
    user_permissions = current_user.get("permissions", [])
    
    if "admin" not in user_roles and "*" not in user_permissions:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="权限不足: 需要管理员角色"
        )
    return current_user